using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Linq;
using Lily.TestHelper.UI;
using White.Core;
using White.Core.UIItems.Finders;
using White.Core.UIItems.ListBoxItems;
using White.Core.UIItems;
using White.Core.UIItems.TabItems;
using White.Core.UIItems.TableItems;
using White.Core.UIItems.WindowItems;

namespace Lily.TestHelper.White
{
	public class WhiteWindowDriver : IWindowDriver
	{
		private readonly Application _application;
		private Window _window;

/*		public WhiteDriver(String pathToExe, string defaultWindow)
		{
			_application = Application.Launch(pathToExe);
			_window = _application.GetWindow(defaultWindow);
		}*/

		 public WhiteWindowDriver(Window window)
        {
            _window = window;
        }

		public string CurrentFormName
		{
			get { return _window.Name; }
		}


		public void ClickButton(string value)
		{
			var button = GetButton(value);
			button.Click();
		}


		public void ClickTab(string name)
		{
			var tab = GetTabPage(name);
			tab.Click();
		}

		public void AssertCurrentTab(string name)
		{
			var tab = GetTabPage(name);
			tab.IsSelected.ShouldBe(true);
		}

		public void ClickLink(string value)
		{
			Hyperlink link = GetLink(value);
			link.Click();
		}

		public string GetValue(string name)
		{
			TextBox textBox = _window.Get<TextBox>(name);
			if (textBox != null)
			{
				return textBox.Text;
			}
			Button button = _window.Get<Button>(name);
			if (button != null)
			{
				return button.Name; 
			}
			Spinner spinner = _window.Get<Spinner>(name);
			if (spinner != null)
			{
				return spinner.Value.ToString();
			}
			CheckBox checkBox = _window.Get<CheckBox>(name);
			if (checkBox != null)
			{
				return checkBox.Checked.ToString();
			}
			ComboBox combobox = _window.Get<ComboBox>(name);
			if (combobox != null)
			{
				return combobox.SelectedItemText;
			}

			throw new Exception(string.Format("Could not find field '{0}' on form.", name)); 
		}

		public void SetValue(string name, string value)
		{
			var textBox = GetTextBox(name);
			if (textBox != null)
			{
				textBox.Text = value;
				return;
			}
			var listBox = GetListBox(name);
			if (listBox != null)
			{
				listBox.Check(value);
				return;
			}
			var spinner = GetSpinner(name);
			if (spinner != null)
			{
				spinner.Value = double.Parse(value);
				return;
			}
			var checkBox = GetCheckBox(name);
			if (checkBox != null)
			{
				checkBox.Checked = Boolean.Parse(value);
				return;
			}
			var combobox = GetComboBox(name);
			if (combobox != null)
			{
				combobox.Select(value);
				return;
			}

            throw new InvalidOperationException("Could not find an Element by the name " + name);
		}

		public ITableDriver SelectTable(string name)
		{
			Table table = GetTable(name);
			ITableDriver tableDriver = new WhiteTableDriver(table);
			return tableDriver;
		}

		private TElement GetElement<TElement>(IEnumerable<string> prependers, string name) where TElement : UIItem
		{
			foreach (var prepender in prependers)
			{
				var element = _window.Get(SearchCriteria.ByAutomationId(prepender + name).AndControlType(typeof(TElement)));
				if (element != null)
				{
					return (TElement)element;
				}
				if (typeof(TElement) == typeof(Button) || typeof(TElement) == typeof(TabPage))
				{
					element = _window.Get(SearchCriteria.ByText(name));
					if (element != null)
					{
						return (TElement)element;
					}
				}
			}
			return null;
		}

		private TabPage GetTabPage(string name)
		{
			return GetElement<TabPage>(new List<string> { string.Empty, "tab" }, name);
		}

		private Table GetTable(string name)
		{
			return GetElement<Table>(new List<string> { string.Empty, "dgv" }, name);
		}

		private TextBox GetTextBox(string name)
		{
			return GetElement<TextBox>(new List<string> { "", "txt" }, name);
		}

		private Button GetButton(string name)
		{
			return GetElement<Button>(new List<string> { "", "btn" }, name);
		}

		private Label GetReadonlyField(string name)
		{
			return GetElement<Label>(new List<string> { string.Empty, "lb" }, name);
		}

		private Hyperlink GetLink(string name)
		{
			return GetElement<Hyperlink>(new List<string> { "", "link" }, name);
		}

		private ListBox GetListBox(string name)
		{
			return GetElement<ListBox>(new List<string> { "" }, name);
		}

		private Spinner GetSpinner(string name)
		{
			return GetElement<Spinner>(new List<string> { "" }, name);
		}

		private CheckBox GetCheckBox(string name)
		{
			return GetElement<CheckBox>(new List<string> { "", "chk" }, name);
		}

		private ComboBox GetComboBox(string name)
		{
			return GetElement<ComboBox>(new List<string> { "", "cb" }, name);
		}

		public IWindowDriver SelectForm(string formName)
		{
			_window = _application.GetWindow(formName);
			return this;
		}

		public IWindowDriver SelectChildModal(string formName)
		{
			return new WhiteWindowDriver(_window.ModalWindow(formName));
		}

		public void CloseForm()
		{
			_window.Close();
		}

		public void ScreenCaptureOnFailure(Action action)
		{
			try
			{
				action();
			}
			catch (Exception)
			{
				CaptureScreenShot(GetTestname());
				throw;
			}
		}

		public void CaptureScreenShot(string testname)
		{
			new ImageSaver().SaveImage(_window.VisibleImage, @".\" + testname + ".jpg", ImageFormat.Jpeg);
		}

		public virtual string GetTestname()
		{
			var stack = new StackTrace();
			StackFrame testMethodFrame =
				stack.GetFrames().Where(
					frame => frame.GetMethod().ReflectedType.Assembly != GetType().Assembly).
					FirstOrDefault();
			return testMethodFrame.GetMethod().Name;
		}

	}
}